﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using GBPVR.Public;
using GBPVRX2.UiSupport;
using System.Drawing;
using System.Xml;
using GBPVRLibrary.UtilityLibrary;

namespace GBPVRLibrary.ControlLibrary
{
    public class PopupMenu:GuiElement
    {
        private UiStatic Background { get; set; }
        private Hashtable Parameters { get; set; }
        private Stack<PopupMenuContainer> Menus { get; set; }
        private PopupMenuContainer CurrentMenu { get { return Menus.Peek(); } }
        private float HorizontalSpacing { get; set; }
        private float VerticalSpacing { get; set; }
        private int Rows { get; set; }
        private RectangleF ItemsLocation { get; set; }
        private PopupMenuItem BackItem { get; set; }
        private PointF SelectedButtonOffset { get; set; }

        private int SelectedIndex { get; set; }
        private int StartPosition { get; set; }

        public PopupMenu()
        {
            this.Menus = new Stack<PopupMenuContainer>();
            Parameters = new Hashtable();
            Background = new UiStatic(SkinHelper, "PopupMenu", Parameters);
            XmlNode node = SkinHelper.getPlacementNode("PopupMenu");
            HorizontalSpacing = float.Parse(node.Attributes["horizontalSpacing"] == null ? "0" : node.Attributes["horizontalSpacing"].Value);
            VerticalSpacing = float.Parse(node.Attributes["verticalSpacing"] == null ? "0" : node.Attributes["verticalSpacing"].Value);
            //SelectedButtonOffset = SkinHelper.getPlacementAttributePos("PopupMenu", "selectedButtonOffset");
            Rows = int.Parse(node.Attributes["rows"] == null ? "0" : node.Attributes["rows"].Value);
            ItemsLocation = SkinHelper.getPlacementRect("PopupMenu-Items");
            this.Location = SkinHelper.getPlacementRect("PopupMenu");
            this.Visible = false;
            BackItem = new PopupMenuItem() { Name = "Back" };
            BackItem.Clicked += new PopupMenuItem.PopupMenuItemClicked_EventHandler(BackItem_Clicked);
        }

        void BackItem_Clicked(object sender, PopupMenuItemEventArgs e)
        {
            Menus.Pop();
            SelectedIndex = CurrentMenu.SelectedIndex;
            StartPosition = CurrentMenu.StartPosition;            
        }

        protected override void Render(System.Collections.ArrayList RenderList, ref bool RequiresMoreRendering)
        {
            Parameters["@Title"] = CurrentMenu.Name;
            Background.SetArgs(Parameters);
            RenderList.AddRange(Background.GetRenderList());
            RectangleF location = new RectangleF(ItemsLocation.Location, ItemsLocation.Size);
            location.X += this.Location.X;
            location.Y += this.Location.Y;
            for (int i = StartPosition; i < NumberOfItems && i - StartPosition < Rows; i++)
            {
                if (CurrentMenu.Items.Count <= i)
                {
                    // must be the back key
                    BackItem.Selected = i == SelectedIndex;
                    BackItem.Location = location;
                    BackItem.RenderElement(RenderList, ref RequiresMoreRendering);
                }
                else
                {
                    CurrentMenu.Items[i].Selected = i == SelectedIndex;
                    CurrentMenu.Items[i].Location = location;
                    CurrentMenu.Items[i].RenderElement(RenderList, ref RequiresMoreRendering);
                }
                location.Y += VerticalSpacing;
                location.X += HorizontalSpacing;
            }
        }

        public void InitializeList(string Title, List<PopupMenuItem> Items)
        {
            SelectedIndex = 0;
            StartPosition = 0;
            Menus.Clear();
            Menus.Push(new PopupMenuContainer() { Items = Items, Name = Title, SelectedIndex = 0, StartPosition = 0 });
        }

        public override bool OnKeyDown(System.Windows.Forms.KeyEventArgs e)
        {
            switch (KeyMapper.GetControlKey(e))
            {
                case KeyMapper.ControlKey.Back:
                    if (Menus.Count > 1)
                    {
                        Menus.Pop();
                        SelectedIndex = CurrentMenu.SelectedIndex;
                        StartPosition = CurrentMenu.StartPosition;
                    }
                    else
                    {
                        this.Visible = false;
                    }
                    return true;
                case KeyMapper.ControlKey.Enter:
                    if (SelectedIndex < CurrentMenu.Items.Count)
                    {
                        CurrentMenu.Items[SelectedIndex].OnKeyDown(e);
                        if (CurrentMenu.Items[SelectedIndex].Items != null && CurrentMenu.Items[SelectedIndex].Items.Count > 0)
                        {
                            CurrentMenu.SelectedIndex = SelectedIndex;
                            CurrentMenu.StartPosition = StartPosition;
                            Menus.Push(new PopupMenuContainer() { Name = CurrentMenu.Items[SelectedIndex].Name, Items = CurrentMenu.Items[SelectedIndex].Items });
                            SelectedIndex = 0;
                            StartPosition = 0;
                        }
                    }
                    else
                    {
                        BackItem.OnKeyDown(e);
                    }
                    return true;
                case KeyMapper.ControlKey.DirectionDown:
                    if (SelectedIndex + 1 < NumberOfItems)
                        SelectedIndex++;
                    else
                        SelectedIndex = 0;
                    return true;
                case KeyMapper.ControlKey.DirectionUp:
                    if (SelectedIndex - 1 >= 0)
                        SelectedIndex--;
                    else
                        SelectedIndex = NumberOfItems - 1;
                    return true;
            }
            return base.OnKeyDown(e);
        }

        private int NumberOfItems
        {
            get
            {
                if (Menus.Count < 2)
                    return CurrentMenu.Items.Count;
                return CurrentMenu.Items.Count + 1; // add one for the "Back" key
            }

        }

        public override void Dispose()
        {
            foreach (PopupMenuContainer container in Menus)
            {
                foreach (PopupMenuItem item in container.Items)
                    item.Dispose();
                container.Items.Clear();
            }
            Menus.Clear();
            Menus = null;
            BackItem.Clicked -= BackItem_Clicked;
            BackItem = null;
            Background.Dispose();
            Background = null;
            Parameters.Clear();
            Parameters = null;
        }
    }

    class PopupMenuContainer
    {
        public List<PopupMenuItem> Items{get;set;}
        public string Name { get; set; }
        public int SelectedIndex { get; set; }
        public int StartPosition { get; set; }
    }

    public class PopupMenuItem:GuiElement, IDisposable
    {
        public string Name { get; set; }
        public List<PopupMenuItem> Items { get; set; }
        public delegate void PopupMenuItemClicked_EventHandler(object Sender, PopupMenuItemEventArgs e);
        public event PopupMenuItemClicked_EventHandler Clicked;
        public bool Selected { get; set; }
        private Hashtable Parameters = new Hashtable();

        /// <summary>
        /// Gets or sets a reference parameter, useful to use in the Clicked event
        /// </summary>
        public object ReferenceParameter { get; set; }

        private UiStatic NormalButton { get; set; }
        private UiStatic SelectedButton { get; set; }

        protected override void Render(ArrayList RenderList, ref bool RequiresMoreRendering)
        {
            UiStatic button = null;
            if (Selected)
            {
                if (SelectedButton == null)
                    SelectedButton = new UiStatic(SkinHelper, "PopupMenu-Item-Selected", new Hashtable());
                button = SelectedButton;
            }
            else
            {
                if (NormalButton == null)
                    NormalButton = new UiStatic(SkinHelper, "PopupMenu-Item-Normal", new Hashtable());
                button = NormalButton;
            }
            Parameters["@Text"] = this.Name;
            button.SetArgs(Parameters);
            button.SetLocation(this.Location.Location);
            RenderList.AddRange(button.GetRenderList());
        }

        public override bool OnKeyDown(System.Windows.Forms.KeyEventArgs e)
        {
            switch (KeyMapper.GetControlKey(e))
            {
                case KeyMapper.ControlKey.Enter:

                    if (Clicked != null)
                        Clicked(this, new PopupMenuItemEventArgs() { Name = this.Name, ReferenceParameter = this.ReferenceParameter });
                    break; // dont return true!!!
            }
            return base.OnKeyDown(e);
        }

        public override void Dispose()
        {
            if(Parameters != null)
                Parameters.Clear();
            Parameters = null;
            if(NormalButton != null)
                NormalButton.Dispose();
            NormalButton = null;
            if(SelectedButton != null)
                SelectedButton.Dispose();
            SelectedButton = null;
            foreach (PopupMenuItemClicked_EventHandler del in Clicked.GetInvocationList())
                Clicked -= del;
        }
    }

    public class PopupMenuItemEventArgs : EventArgs
    {
        public string Name { get; set; }
        public object ReferenceParameter { get; set; }
    }
}
